home *** CD-ROM | disk | FTP | other *** search
/ Clickx 96 / Clickx 96.iso / software / tools / tool / xbmc-10.1.exe / addons / script.module.pil / lib / PIL / ImageFile.py < prev    next >
Encoding:
Python Source  |  2009-04-06  |  14.9 KB  |  529 lines

  1. #
  2. # The Python Imaging Library.
  3. # $Id$
  4. #
  5. # base class for image file handlers
  6. #
  7. # history:
  8. # 1995-09-09 fl   Created
  9. # 1996-03-11 fl   Fixed load mechanism.
  10. # 1996-04-15 fl   Added pcx/xbm decoders.
  11. # 1996-04-30 fl   Added encoders.
  12. # 1996-12-14 fl   Added load helpers
  13. # 1997-01-11 fl   Use encode_to_file where possible
  14. # 1997-08-27 fl   Flush output in _save
  15. # 1998-03-05 fl   Use memory mapping for some modes
  16. # 1999-02-04 fl   Use memory mapping also for "I;16" and "I;16B"
  17. # 1999-05-31 fl   Added image parser
  18. # 2000-10-12 fl   Set readonly flag on memory-mapped images
  19. # 2002-03-20 fl   Use better messages for common decoder errors
  20. # 2003-04-21 fl   Fall back on mmap/map_buffer if map is not available
  21. # 2003-10-30 fl   Added StubImageFile class
  22. # 2004-02-25 fl   Made incremental parser more robust
  23. #
  24. # Copyright (c) 1997-2004 by Secret Labs AB
  25. # Copyright (c) 1995-2004 by Fredrik Lundh
  26. #
  27. # See the README file for information on usage and redistribution.
  28. #
  29.  
  30. import Image
  31. import traceback, string, os
  32.  
  33. MAXBLOCK = 65536
  34.  
  35. SAFEBLOCK = 1024*1024
  36.  
  37. ERRORS = {
  38.     -1: "image buffer overrun error",
  39.     -2: "decoding error",
  40.     -3: "unknown error",
  41.     -8: "bad configuration",
  42.     -9: "out of memory error"
  43. }
  44.  
  45. def raise_ioerror(error):
  46.     try:
  47.         message = Image.core.getcodecstatus(error)
  48.     except AttributeError:
  49.         message = ERRORS.get(error)
  50.     if not message:
  51.         message = "decoder error %d" % error
  52.     raise IOError(message + " when reading image file")
  53.  
  54. #
  55. # --------------------------------------------------------------------
  56. # Helpers
  57.  
  58. def _tilesort(t1, t2):
  59.     # sort on offset
  60.     return cmp(t1[2], t2[2])
  61.  
  62. #
  63. # --------------------------------------------------------------------
  64. # ImageFile base class
  65.  
  66. ##
  67. # Base class for image file handlers.
  68.  
  69. class ImageFile(Image.Image):
  70.     "Base class for image file format handlers."
  71.  
  72.     def __init__(self, fp=None, filename=None):
  73.         Image.Image.__init__(self)
  74.  
  75.         self.tile = None
  76.         self.readonly = 1 # until we know better
  77.  
  78.         self.decoderconfig = ()
  79.         self.decodermaxblock = MAXBLOCK
  80.  
  81.         if Image.isStringType(fp):
  82.             # filename
  83.             self.fp = open(fp, "rb")
  84.             self.filename = fp
  85.         else:
  86.             # stream
  87.             self.fp = fp
  88.             self.filename = filename
  89.  
  90.         try:
  91.             self._open()
  92.         except IndexError, v: # end of data
  93.             if Image.DEBUG > 1:
  94.                 traceback.print_exc()
  95.             raise SyntaxError, v
  96.         except TypeError, v: # end of data (ord)
  97.             if Image.DEBUG > 1:
  98.                 traceback.print_exc()
  99.             raise SyntaxError, v
  100.         except KeyError, v: # unsupported mode
  101.             if Image.DEBUG > 1:
  102.                 traceback.print_exc()
  103.             raise SyntaxError, v
  104.         except EOFError, v: # got header but not the first frame
  105.             if Image.DEBUG > 1:
  106.                 traceback.print_exc()
  107.             raise SyntaxError, v
  108.  
  109.         if not self.mode or self.size[0] <= 0:
  110.             raise SyntaxError, "not identified by this driver"
  111.  
  112.     def draft(self, mode, size):
  113.         "Set draft mode"
  114.  
  115.         pass
  116.  
  117.     def verify(self):
  118.         "Check file integrity"
  119.  
  120.         # raise exception if something's wrong.  must be called
  121.         # directly after open, and closes file when finished.
  122.         self.fp = None
  123.  
  124.     def load(self):
  125.         "Load image data based on tile list"
  126.  
  127.         pixel = Image.Image.load(self)
  128.  
  129.         if self.tile is None:
  130.             raise IOError("cannot load this image")
  131.         if not self.tile:
  132.             return pixel
  133.  
  134.         self.map = None
  135.  
  136.         readonly = 0
  137.  
  138.         if self.filename and len(self.tile) == 1:
  139.             # try memory mapping
  140.             d, e, o, a = self.tile[0]
  141.             if d == "raw" and a[0] == self.mode and a[0] in Image._MAPMODES:
  142.                 try:
  143.                     if hasattr(Image.core, "map"):
  144.                         # use built-in mapper
  145.                         self.map = Image.core.map(self.filename)
  146.                         self.map.seek(o)
  147.                         self.im = self.map.readimage(
  148.                             self.mode, self.size, a[1], a[2]
  149.                             )
  150.                     else:
  151.                         # use mmap, if possible
  152.                         import mmap
  153.                         file = open(self.filename, "r+")
  154.                         size = os.path.getsize(self.filename)
  155.                         # FIXME: on Unix, use PROT_READ etc
  156.                         self.map = mmap.mmap(file.fileno(), size)
  157.                         self.im = Image.core.map_buffer(
  158.                             self.map, self.size, d, e, o, a
  159.                             )
  160.                     readonly = 1
  161.                 except (AttributeError, EnvironmentError, ImportError):
  162.                     self.map = None
  163.  
  164.         self.load_prepare()
  165.  
  166.         # look for read/seek overrides
  167.         try:
  168.             read = self.load_read
  169.         except AttributeError:
  170.             read = self.fp.read
  171.  
  172.         try:
  173.             seek = self.load_seek
  174.         except AttributeError:
  175.             seek = self.fp.seek
  176.  
  177.         if not self.map:
  178.  
  179.             # sort tiles in file order
  180.             self.tile.sort(_tilesort)
  181.  
  182.             try:
  183.                 # FIXME: This is a hack to handle TIFF's JpegTables tag.
  184.                 prefix = self.tile_prefix
  185.             except AttributeError:
  186.                 prefix = ""
  187.  
  188.             for d, e, o, a in self.tile:
  189.                 d = Image._getdecoder(self.mode, d, a, self.decoderconfig)
  190.                 seek(o)
  191.                 try:
  192.                     d.setimage(self.im, e)
  193.                 except ValueError:
  194.                     continue
  195.                 b = prefix
  196.                 t = len(b)
  197.                 while 1:
  198.                     s = read(self.decodermaxblock)
  199.                     if not s:
  200.                         self.tile = []
  201.                         raise IOError("image file is truncated (%d bytes not processed)" % len(b))
  202.                     b = b + s
  203.                     n, e = d.decode(b)
  204.                     if n < 0:
  205.                         break
  206.                     b = b[n:]
  207.                     t = t + n
  208.  
  209.         self.tile = []
  210.         self.readonly = readonly
  211.  
  212.         self.fp = None # might be shared
  213.  
  214.         if not self.map and e < 0:
  215.             raise_ioerror(e)
  216.  
  217.         # post processing
  218.         if hasattr(self, "tile_post_rotate"):
  219.             # FIXME: This is a hack to handle rotated PCD's
  220.             self.im = self.im.rotate(self.tile_post_rotate)
  221.             self.size = self.im.size
  222.  
  223.         self.load_end()
  224.  
  225.         return Image.Image.load(self)
  226.  
  227.     def load_prepare(self):
  228.         # create image memory if necessary
  229.         if not self.im or\
  230.            self.im.mode != self.mode or self.im.size != self.size:
  231.             self.im = Image.core.new(self.mode, self.size)
  232.         # create palette (optional)
  233.         if self.mode == "P":
  234.             Image.Image.load(self)
  235.  
  236.     def load_end(self):
  237.         # may be overridden
  238.         pass
  239.  
  240.     # may be defined for contained formats
  241.     # def load_seek(self, pos):
  242.     #     pass
  243.  
  244.     # may be defined for blocked formats (e.g. PNG)
  245.     # def load_read(self, bytes):
  246.     #     pass
  247.  
  248. ##
  249. # Base class for stub image loaders.
  250. # <p>
  251. # A stub loader is an image loader that can identify files of a
  252. # certain format, but relies on external code to load the file.
  253.  
  254. class StubImageFile(ImageFile):
  255.     "Base class for stub image loaders."
  256.  
  257.     def _open(self):
  258.         raise NotImplementedError(
  259.             "StubImageFile subclass must implement _open"
  260.             )
  261.  
  262.     def load(self):
  263.         loader = self._load()
  264.         if loader is None:
  265.             raise IOError("cannot find loader for this %s file" % self.format)
  266.         image = loader.load(self)
  267.         assert image is not None
  268.         # become the other object (!)
  269.         self.__class__ = image.__class__
  270.         self.__dict__ = image.__dict__
  271.  
  272.     ##
  273.     # (Hook) Find actual image loader.
  274.  
  275.     def _load(self):
  276.         raise NotImplementedError(
  277.             "StubImageFile subclass must implement _load"
  278.             )
  279.  
  280. ##
  281. # (Internal) Support class for the <b>Parser</b> file.
  282.  
  283. class _ParserFile:
  284.     # parser support class.
  285.  
  286.     def __init__(self, data):
  287.         self.data = data
  288.         self.offset = 0
  289.  
  290.     def close(self):
  291.         self.data = self.offset = None
  292.  
  293.     def tell(self):
  294.         return self.offset
  295.  
  296.     def seek(self, offset, whence=0):
  297.         if whence == 0:
  298.             self.offset = offset
  299.         elif whence == 1:
  300.             self.offset = self.offset + offset
  301.         else:
  302.             # force error in Image.open
  303.             raise IOError("illegal argument to seek")
  304.  
  305.     def read(self, bytes=0):
  306.         pos = self.offset
  307.         if bytes:
  308.             data = self.data[pos:pos+bytes]
  309.         else:
  310.             data = self.data[pos:]
  311.         self.offset = pos + len(data)
  312.         return data
  313.  
  314.     def readline(self):
  315.         # FIXME: this is slow!
  316.         s = ""
  317.         while 1:
  318.             c = self.read(1)
  319.             if not c:
  320.                 break
  321.             s = s + c
  322.             if c == "\n":
  323.                 break
  324.         return s
  325.  
  326. ##
  327. # Incremental image parser.  This class implements the standard
  328. # feed/close consumer interface.
  329.  
  330. class Parser:
  331.  
  332.     incremental = None
  333.     image = None
  334.     data = None
  335.     decoder = None
  336.     finished = 0
  337.  
  338.     ##
  339.     # (Consumer) Reset the parser.  Note that you can only call this
  340.     # method immediately after you've created a parser; parser
  341.     # instances cannot be reused.
  342.  
  343.     def reset(self):
  344.         assert self.data is None, "cannot reuse parsers"
  345.  
  346.     ##
  347.     # (Consumer) Feed data to the parser.
  348.     #
  349.     # @param data A string buffer.
  350.     # @exception IOError If the parser failed to parse the image file.
  351.  
  352.     def feed(self, data):
  353.         # collect data
  354.  
  355.         if self.finished:
  356.             return
  357.  
  358.         if self.data is None:
  359.             self.data = data
  360.         else:
  361.             self.data = self.data + data
  362.  
  363.         # parse what we have
  364.         if self.decoder:
  365.  
  366.             if self.offset > 0:
  367.                 # skip header
  368.                 skip = min(len(self.data), self.offset)
  369.                 self.data = self.data[skip:]
  370.                 self.offset = self.offset - skip
  371.                 if self.offset > 0 or not self.data:
  372.                     return
  373.  
  374.             n, e = self.decoder.decode(self.data)
  375.  
  376.             if n < 0:
  377.                 # end of stream
  378.                 self.data = None
  379.                 self.finished = 1
  380.                 if e < 0:
  381.                     # decoding error
  382.                     self.image = None
  383.                     raise_ioerror(e)
  384.                 else:
  385.                     # end of image
  386.                     return
  387.             self.data = self.data[n:]
  388.  
  389.         elif self.image:
  390.  
  391.             # if we end up here with no decoder, this file cannot
  392.             # be incrementally parsed.  wait until we've gotten all
  393.             # available data
  394.             pass
  395.  
  396.         else:
  397.  
  398.             # attempt to open this file
  399.             try:
  400.                 try:
  401.                     fp = _ParserFile(self.data)
  402.                     im = Image.open(fp)
  403.                 finally:
  404.                     fp.close() # explicitly close the virtual file
  405.             except IOError:
  406.                 pass # not enough data
  407.             else:
  408.                 flag = hasattr(im, "load_seek") or hasattr(im, "load_read")
  409.                 if flag or len(im.tile) != 1:
  410.                     # custom load code, or multiple tiles
  411.                     self.decode = None
  412.                 else:
  413.                     # initialize decoder
  414.                     im.load_prepare()
  415.                     d, e, o, a = im.tile[0]
  416.                     im.tile = []
  417.                     self.decoder = Image._getdecoder(
  418.                         im.mode, d, a, im.decoderconfig
  419.                         )
  420.                     self.decoder.setimage(im.im, e)
  421.  
  422.                     # calculate decoder offset
  423.                     self.offset = o
  424.                     if self.offset <= len(self.data):
  425.                         self.data = self.data[self.offset:]
  426.                         self.offset = 0
  427.  
  428.                 self.image = im
  429.  
  430.     ##
  431.     # (Consumer) Close the stream.
  432.     #
  433.     # @return An image object.
  434.     # @exception IOError If the parser failed to parse the image file.
  435.  
  436.     def close(self):
  437.         # finish decoding
  438.         if self.decoder:
  439.             # get rid of what's left in the buffers
  440.             self.feed("")
  441.             self.data = self.decoder = None
  442.             if not self.finished:
  443.                 raise IOError("image was incomplete")
  444.         if not self.image:
  445.             raise IOError("cannot parse this image")
  446.         if self.data:
  447.             # incremental parsing not possible; reopen the file
  448.             # not that we have all data
  449.             try:
  450.                 fp = _ParserFile(self.data)
  451.                 self.image = Image.open(fp)
  452.             finally:
  453.                 self.image.load()
  454.                 fp.close() # explicitly close the virtual file
  455.         return self.image
  456.  
  457. # --------------------------------------------------------------------
  458.  
  459. ##
  460. # (Helper) Save image body to file.
  461. #
  462. # @param im Image object.
  463. # @param fp File object.
  464. # @param tile Tile list.
  465.  
  466. def _save(im, fp, tile):
  467.     "Helper to save image based on tile list"
  468.  
  469.     im.load()
  470.     if not hasattr(im, "encoderconfig"):
  471.         im.encoderconfig = ()
  472.     tile.sort(_tilesort)
  473.     # FIXME: make MAXBLOCK a configuration parameter
  474.     bufsize = max(MAXBLOCK, im.size[0] * 4) # see RawEncode.c
  475.     try:
  476.         fh = fp.fileno()
  477.         fp.flush()
  478.     except AttributeError:
  479.         # compress to Python file-compatible object
  480.         for e, b, o, a in tile:
  481.             e = Image._getencoder(im.mode, e, a, im.encoderconfig)
  482.             if o > 0:
  483.                 fp.seek(o, 0)
  484.             e.setimage(im.im, b)
  485.             while 1:
  486.                 l, s, d = e.encode(bufsize)
  487.                 fp.write(d)
  488.                 if s:
  489.                     break
  490.             if s < 0:
  491.                 raise IOError("encoder error %d when writing image file" % s)
  492.     else:
  493.         # slight speedup: compress to real file object
  494.         for e, b, o, a in tile:
  495.             e = Image._getencoder(im.mode, e, a, im.encoderconfig)
  496.             if o > 0:
  497.                 fp.seek(o, 0)
  498.             e.setimage(im.im, b)
  499.             s = e.encode_to_file(fh, bufsize)
  500.             if s < 0:
  501.                 raise IOError("encoder error %d when writing image file" % s)
  502.     try:
  503.         fp.flush()
  504.     except: pass
  505.  
  506.  
  507. ##
  508. # Reads large blocks in a safe way.  Unlike fp.read(n), this function
  509. # doesn't trust the user.  If the requested size is larger than
  510. # SAFEBLOCK, the file is read block by block.
  511. #
  512. # @param fp File handle.  Must implement a <b>read</b> method.
  513. # @param size Number of bytes to read.
  514. # @return A string containing up to <i>size</i> bytes of data.
  515.  
  516. def _safe_read(fp, size):
  517.     if size <= 0:
  518.         return ""
  519.     if size <= SAFEBLOCK:
  520.         return fp.read(size)
  521.     data = []
  522.     while size > 0:
  523.         block = fp.read(min(size, SAFEBLOCK))
  524.         if not block:
  525.             break
  526.         data.append(block)
  527.         size = size - len(block)
  528.     return string.join(data, "")
  529.